package com.markhsiu.httpserver.event.formparse;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.markhsiu.common.ConstantUtil;
import com.markhsiu.common.memory.ByteBuff;
import com.markhsiu.common.memory.HeapByteBuff;
import com.markhsiu.httpserver.event.HttpProtocol;
import com.markhsiu.httpserver.event.Request;

/**
 * 文件表单解析
 * 
 * 数据格式
 * 
 * =========================================================================
 * -----------------------------22171225728510 Content-Disposition: form-data; name="username"
 * 
 * 123123 
 * -----------------------------22171225728510 Content-Disposition: form-data; name="name" 
 * 
 * 12312 
 * -----------------------------22171225728510 
 * Content-Disposition: form-data; name="pic"; filename="he.txt" 
 * Content-Type: text/plain
 * 
 * #################data#################
 * -----------------------------22171225728510--
 * 
 * =========================================================================
 */
public class FileFormParse {

	private static final int DEFAULT_BUFSIZE = 2048;
	private Map<String, String> params = new HashMap<String, String>();
	private List<FileFormItem> files = new ArrayList<>();
	private Request request;
	private byte[] data;
	private final byte[] boundary;//separates the various parts.

	public FileFormParse(Request request) {
		this.request = request;
		
		//Content-Type: multipart/form-data; boundary=---------------------------122872775310383
		String contentType = this.request.getContentType();
		System.out.println("contentType || "+contentType);
		this.boundary = contentType.split(";")[1].split("=")[1].getBytes();
		System.out.println("boundary  || "+new String(boundary));
	}

	public FileFormParse execute() throws UnsupportedEncodingException {
		data = read();
		
//		System.out.println(data.length);
//		StringBuilder sb = new StringBuilder();
//		for (byte b : data) {
//			sb.append((char)b);
//		}
//		System.out.println(sb);
//		System.out.println("======================");
		int index = 0;
		int row = 1;
		int length = data.length;
		boolean newFeild = false;
		ByteBuff buff = HeapByteBuff.allocate(128);
		for (; index < length;) {
			if(newFeild && checkRowEnd(index)){	
				break;
			}
			
			if (row == 1) {
				index = skipRow(index);
				row++;
				newFeild = false;
				continue;
			}

			if (row == 2) {
				buff.clear();
				index = readBytes(index, buff);
				String[] array = ConstantUtil.bytesUTF(buff.data()).split("; ");
				if(array.length > 1){
					int eq = array[1].indexOf("=");
					int len = array[1].length();
					String name = array[1].substring(eq+2, len - 1);
					//文件
					if(array.length > 2 && array[2].indexOf("filename") > -1){
						index = skipRow(index);
						index = skipRow(index);
						
						FileFormItem fileForm = new FileFormItem();
						index = readFile(index, fileForm);
						fileForm.setFileField(true);
						fileForm.setFeildName(name);
						fileForm.setName(array[2].substring(array[2].indexOf("=")+2, array[2].length() - 1));
						files.add(fileForm);
					} else {
						buff.clear();
						index = skipRow(index);
						
						index = readBytes(index, buff);
						params.put(name,ConstantUtil.bytesUTF(buff.data()));
					}
				}
				
				
				row = 1;
				newFeild = true;
				continue;
			}
		}
		return this;
	}


	private int skipRow(int index){
		while(true){
			if (checkRowEnd(index)) {
				index += 2;
				break;
			} else {
				index ++;
			}
		}
		return index;
	}
	
	private int readBytes(int index,ByteBuff buff) {
		while (true) {
			if (checkRowEnd(index)) {
				index += 2;
				break;
			}
			buff.put( data[index++]);
		}
		return index;
	}
	
	private int readFile(int index,FileFormItem fileForm) {
		ByteBuff buff = HeapByteBuff.allocate(2048);
		
		while (true) {
			if (checkRowNextNull(index)) {
				index += 2;
				break;
			}
			buff.put(data[index++]);
		}
		fileForm.setBody(buff.data());
		fileForm.setLength(buff.length());
		return index;
	}
	
	private boolean checkRowEnd(int index){
		return data[index] == HttpProtocol.ASCII_CR && data[index + 1] == HttpProtocol.ASCII_LF;
	}
	
	private boolean checkRowNextNull(int index){
		return checkRowEnd(index)  ;
	}

	public Map<String, String> getResult() {
		return params;
	}

	public List<FileFormItem> getfiles() {
		return files;
	}
	
	private byte[] read() {
		ByteArrayOutputStream data = new ByteArrayOutputStream();
		InputStream input = request.getInputStream();
		try {

			byte[] buff = new byte[DEFAULT_BUFSIZE];
			int rc = 0;
			while (true) {
				rc = input.read(buff, 0, DEFAULT_BUFSIZE);
				data.write(buff, 0, rc);
				if (rc < DEFAULT_BUFSIZE) {
					break;
				}
			}
		} catch (IOException ee) {
			ee.printStackTrace();
		}
		return data.toByteArray();
	}
}
